package com.sscl.baselibrary.adapter

import android.content.Context
import android.graphics.Bitmap
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.annotation.*
import androidx.viewbinding.ViewBinding
import androidx.viewbinding.ViewBindings
import com.sscl.baselibrary.exts.saveAs
import com.sscl.baselibrary.exts.saveAsUnChecked
import java.lang.reflect.ParameterizedType

/**
 * ListView或Spinner的万能适配器
 *
 * @author alm
 */
abstract class BaseViewBindingPurposeAdapter<VB : ViewBinding, T> constructor(
    /**
     * 适配器数据源
     */
    protected var mData: MutableList<T>,
) : BaseAdapter() {

    /*--------------------------------静态常量--------------------------------*/

    @Suppress("PropertyName")
    protected val TAG: String = javaClass.simpleName

    /*--------------------------------成员变量--------------------------------*/
    /**
     * 上下文弱引用
     */
    private var mContext: Context? = null

    /**
     * 自定义适配器总数(适配器会根据这个数与数据源的比例来显示)
     */
    private var mCountSum: Int = -1
    /*--------------------------------实现父类方法--------------------------------*/
    /**
     * How many items are in the data set represented by this Adapter.
     *
     * @return Count of items.
     */
    override fun getCount(): Int {
        return if (mCountSum == -1) {
            mData.size
        } else {
            mCountSum
        }
    }

    /**
     * Get the data item associated with the specified position in the data set.
     *
     * @param position Position of the item whose data we want within the adapter's
     * data set.
     * @return The data at the specified position.
     */
    override fun getItem(position: Int): T {
        return if (mCountSum == -1) {
            mData[position]
        } else {
            mData[mCountSum % mData.size]
        }
    }

    /**
     * Get the row id associated with the specified position in the list.
     *
     * @param position The position of the item within the adapter's data set whose row id we want.
     * @return The id of the item at the specified position.
     */
    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    /**
     * Get a View that displays the data at the specified position in the data set. You can either
     * create a View manually or inflate it from an XML layout file. When the View is inflated, the
     * parent View (GridView, ListView...) will apply default layout parameters unless you use
     * [LayoutInflater.inflate]
     * to specify a root view and to prevent attachment to the root.
     *
     * @param position    The position of the item within the adapter's data set of the item whose view
     * we want.
     * @param convertView The old view to reuse, if possible. Note: You should check that this view
     * is non-null and of an appropriate type before using. If it is not possible to convert
     * this view to display the correct data, this method can create a new view.
     * Heterogeneous lists can specify their number of view types, so that this View is
     * always of the right type (see [.getViewTypeCount] and
     * [.getItemViewType]).
     * @param parent      The parent that this view will eventually be attached to
     * @return a View corresponding to the data at the specified position.
     */
    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        if (mContext == null) {
            mContext = parent.context
        }
        val viewBindingHolder: ViewBindingHolder<VB> = getViewHolder(convertView, parent)
        convert(viewBindingHolder, position, getItem(position))
        return viewBindingHolder.binding.root
    }

    /*--------------------------------公开方法--------------------------------*/

    /**
     * 更新数据源并刷新适配器进行显示
     *
     * @param dataList 新的数据源
     */
    @Suppress("unused")
    fun refresh(dataList: ArrayList<T>) {
        mData = dataList
        notifyDataSetChanged()
    }

    /*--------------------------------私有方法--------------------------------*/
    /**
     * 获取ViewHolder
     *
     * @param convertView 复用的View
     * @param parent      父布局
     * @return ViewHolder
     */
    private fun getViewHolder(
        convertView: View?,
        parent: ViewGroup
    ): ViewBindingHolder<VB> {
        val context = if (convertView != null) {
            convertView.context
        } else {
            mContext ?: parent.context
        }
        val type = javaClass.genericSuperclass
        val vbClass: Class<VB> = type!!.saveAs<ParameterizedType>().actualTypeArguments[0].saveAs()
        val method = vbClass.getDeclaredMethod("inflate", LayoutInflater::class.java)
        val layoutInflater = LayoutInflater.from(context)
        val binding: VB = method.invoke(context, layoutInflater)!!.saveAsUnChecked()
        return ViewBindingHolder(binding)
    }
    /*--------------------------------抽象方法--------------------------------*/
    /**
     * 每一个单独的选项的内容设置
     *
     * @param viewBindingHolder ViewHolder
     * @param position   position
     * @param item       item
     */
    protected abstract fun convert(
        viewBindingHolder: ViewBindingHolder<VB>,
        position: Int,
        item: T
    )

    /**
     * ListView万能适配器专用的ViewHolder
     *
     * @author alm
     */
    class ViewBindingHolder<VB : ViewBinding> internal constructor(
        /**
         * 当前位置
         */
        val binding: VB
    ) {

        /*--------------------------------构造函数--------------------------------*/

        init {
            binding.root.tag = this
        }
    }
}